package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Service
@RefreshScope
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private CategoryFeignClient categoryFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private AlbumIndexRepository albumIndexRepository;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private SuggestIndexRepository suggestIndexRepository;
    @Value("${ranking.dimension.array}")
    private String rankingDimensionArray;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 专辑上架
     *
     * @param albumId
     */
    @Override
    public void upperAlbum(Long albumId) {
        //首先需要用到的实体类是AlbumInfoIndex,存储上架下架用到的字段
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        //使用多线程进行查询,提升查询效率,选择supplyAsync因为我们下边会用到albumInfo中的三级分类id,去查询视图表
        //供给型函数式接口,无参有返回值
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //赋值:将实体类中的每一个字段都需要进行赋值
            //根据分析,涉及到的表包括album_info,base_category_view,album_stat,
            //albu_info,在当前微服务想要调用其他微服务的方法,要用openFeign,此时就必须要求架构是SpringBoot配合SpringCloud,如果不在同一个架构还想调用就得用httpClient
            //要想使用openFeign就需要用到service-client,这里包含项目中的远程调用
            //album_info 这里有一个细节:刚刚远程调用的接口,返回的结果是albumInfo,所以我们需要在远程调用的时候加上泛型
            //Result albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            //做断言
            Assert.notNull(albumInfoResult, "查询专辑信息失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "获取专辑信息失败");
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            //获取属性和属性值信息--getAlbumInfo中完成的
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            //判断
            if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
                /*//循环遍历赋值
                List<AttributeValueIndex>attributeValueIndexList=new ArrayList<>();
                for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
                    //创建一个对象
                    AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                    attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                    attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                    //赋值--添加到集合
                    attributeValueIndexList.add(attributeValueIndex);
                }
                //添加属性与属性值集合
                albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);*/
                List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                    //创建一个对象
                    AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                    attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                    attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                    return attributeValueIndex;
                }).collect(Collectors.toList());
                //添加属性与属性值集合
                albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            }
            //返回数据
            return albumInfo;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("查询专辑信息失败：{}", throwable.getMessage());
            return null;
        });
        //获取到上一个查询返回的结果,并使用其获取三级分类id,根据三级分类Id查询视图,获取一二三级分类id
        //有参无返回值
        CompletableFuture<Integer> cateCompletableFuture = albumInfoCompletableFuture.thenApplyAsync(albumInfo -> {
            //远程调用三级分类Id获取分类数据 查的是视图表,会对应一个表,这里的返回值就是这张表
            Result<BaseCategoryView> categoryViewResult =
                    categoryFeignClient.getBaseCategoryView(albumInfo.getCategory3Id());
            //判断数据
            Assert.notNull(categoryViewResult, "查询分类数据失败");
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            Assert.notNull(baseCategoryView, "获取分类数据失败");
            //赋值:
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            return 1;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("查询分类数据失败：{}", throwable.getMessage());
            return 0;
        });
        //查询作者信息
        CompletableFuture<Integer> userCompletableFuture = albumInfoCompletableFuture.thenApplyAsync(albumInfo -> {
            //远程调用
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            Assert.notNull(userInfoVoResult, "查询作者信息失败");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "获取作者信息失败");
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
            return 1;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("查询分类数据失败：{}", throwable.getMessage());
            return 0;
        });
        //统计信息:根据专辑id查询专辑的统计数据信息
        albumInfoIndex.setPlayStatNum(new Random().nextInt(10000));
        albumInfoIndex.setCommentStatNum(new Random().nextInt(10000));
        albumInfoIndex.setBuyStatNum(new Random().nextInt(10000));
        albumInfoIndex.setSubscribeStatNum(new Random().nextInt(10000));

        //设置热度排名
        albumInfoIndex.setHotScore(Double.valueOf(new Random().nextInt(10000)));

        //做数据汇总
        //CompletableFuture.allOf(albumInfoCompletableFuture,cateCompletableFuture,userCompletableFuture).join();
        try {
            if (null == albumInfoCompletableFuture.get() || 0 == cateCompletableFuture.get() || 0 == userCompletableFuture.get()) {
                //  获取专辑失败;
                throw new GuiguException(20001, "远程调用获取数据失败");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        //利用es的API,对数据进行保存,也就是说将albumInfoIndex保存到es当中
        albumIndexRepository.save(albumInfoIndex);

        //上架提出库;
        //标题
        SuggestIndex suggestIndex = new SuggestIndex();
        //  赋值：本质赋值的是title;
        suggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndex);
        //介绍
        SuggestIndex suggestIndexInfo = new SuggestIndex();
        //  赋值：本质赋值的是title;
        suggestIndexInfo.setId(UUID.randomUUID().toString().replace("-", ""));
        suggestIndexInfo.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndexInfo.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndexInfo.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndexInfo.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        suggestIndexRepository.save(suggestIndexInfo);
        //作者
        SuggestIndex announcerSuggestIndex = new SuggestIndex();
        announcerSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        announcerSuggestIndex.setTitle(albumInfoIndex.getAnnouncerName());
        announcerSuggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAnnouncerName()}));
        announcerSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAnnouncerName())}));
        announcerSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAnnouncerName())}));
        suggestIndexRepository.save(announcerSuggestIndex);


    }

    /**
     * 自动补全
     *
     * @param keyword
     * @return
     */
    @Override
    public List<String> completeSuggest(String keyword) {
        //编写DSL语句
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(
                    s -> s.index("suggestinfo")
                            .suggest(s1 -> s1.suggesters("suggest_keyword"
                                                    ,
                                                    f -> f.prefix(keyword).completion(c -> c.field("keyword")
                                                            .skipDuplicates(true)
                                                            .fuzzy(f1 -> f1.fuzziness("auto"))
                                                            .size(10))
                                            )
                                            .suggesters("suggest_keywordPinyin"
                                                    ,
                                                    f -> f.prefix(keyword).completion(c -> c.field("keywordPinyin")
                                                            .skipDuplicates(true)
                                                            .fuzzy(f1 -> f1.fuzziness("auto"))
                                                            .size(10))
                                            )
                                            .suggesters("suggest_keywordSequence"
                                                    ,
                                                    f -> f.prefix(keyword).completion(c -> c.field("keywordSequence")
                                                            .skipDuplicates(true)
                                                            .fuzzy(f1 -> f1.fuzziness("auto"))
                                                            .size(10))
                                            )
                            )
                    ,
                    SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取到查询结果集：
        List<String> list = new ArrayList<>();
        //  定义一个方法：
        list.addAll(this.getSuggestList(searchResponse, "suggest_keyword"));
        list.addAll(this.getSuggestList(searchResponse, "suggest_keywordPinyin"));
        list.addAll(this.getSuggestList(searchResponse, "suggest_keywordSequence"));
        //  返回数据
        return list;
    }

    /**
     * 获取提出库数据thread
     *
     * @param searchResponse
     * @param keyword
     * @return
     */
    private Collection<String> getSuggestList(SearchResponse<SuggestIndex> searchResponse, String keyword) {
        //根据key 获取options:
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(keyword);
        if (!CollectionUtils.isEmpty(suggestionList)) {
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
                 /*List<String> list = suggestIndexSuggestion.completion().options().stream().map(option -> {
                 String title = option.source().getTitle();
                 return title;
            }).collect(Collectors.toList());*/
                return suggestIndexSuggestion.completion().options().stream().map(option -> option.source().getTitle()).collect(Collectors.toList());
            }
        }

        //  返回数据
        return new ArrayList<>();
    }


    /**
     * 检索
     * @param albumIndexQuery
     * @return
     */
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //获取到用户检索的DSL语句;
        SearchRequest searchRequest = this.queryBuildDsl(albumIndexQuery);
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 赋值--private List<AlbumInfoIndexVo> list = new ArrayList<>();
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(searchResponse);
        // 其他属性赋值
        albumSearchResponseVo.setTotal(searchResponse.hits().total().value());
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        //计算总页数
        // Long totalPages = albumSearchResponseVo.getTotal()%albumIndexQuery.getPageSize()==0?albumSearchResponseVo.getTotal()/albumIndexQuery.getPageSize():albumSearchResponseVo.getTotal()/albumIndexQuery.getPageSize()+1;
        Long totalPages = (albumSearchResponseVo.getTotal() + albumIndexQuery.getPageSize() - 1) / albumIndexQuery.getPageSize();
        albumSearchResponseVo.setTotalPages(totalPages);
        // 返回数据;
        return albumSearchResponseVo;
    }

    /**
     * 查询结果集,获取检索结果对象
     *
     * @param searchResponse
     * @return
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        //创建一个对象
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        // 赋值--private List<AlbumInfoIndexVo> list = new ArrayList<>();
        List<AlbumInfoIndexVo> list = new ArrayList<>();
        //循环遍历获取hits中的每一个数据
        for (Hit<AlbumInfoIndex> hit : searchResponse.hits().hits()) {
            //获取数据
            AlbumInfoIndex albumInfoIndex = hit.source();
            //创建对象
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            //属性赋值
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            //判断是否有高亮显示
            if (null != hit.highlight().get("albumTitle")) {
                //高亮字段
                String albumTitle = hit.highlight().get("albumTitle").get(0);//因为展示的dsl语句中的结果只有一条数据
                //将高亮字段赋值给对象
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            //将对象添加到集合中
            list.add(albumInfoIndexVo);
        }
        //赋值
        albumSearchResponseVo.setList(list);
        //返回数据
        return albumSearchResponseVo;
    }

    /**
     * 动态生成DSL语句
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest queryBuildDsl(AlbumIndexQuery albumIndexQuery) {
        //SearchRequest本质是DSL语句的封装类
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        //和.build()分开是为了需要根据不同的查询条件逐步添加各种查询参数
        //query里需要调用boolquery---bool查询
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        //指定索引库
        searchRequestBuilder.index("albuminfo");
        //判断
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            //如果keyword不为空,要根据关键词查询
            boolQuery.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("announcerName").query(albumIndexQuery.getKeyword())));

            //设置高亮
            searchRequestBuilder.highlight(h -> h.fields("albumTitle", f -> f.preTags("<span style=color:red>")
                    .postTags("</span>")));
        }
        //分类id
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            //如果一级分类id不为空,根据分类id查询
            boolQuery.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            boolQuery.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            boolQuery.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        //通过属性与属性值进行过滤
        //判断是否有属性和属性值,没有就不用查了@Schema(description = "属性（属性id:属性值id）")
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {
            //循环遍历:用户可能同时选择多个属性进行过滤
            for (String attribute : attributeList) {
                //给属性值切割
                String[] split = attribute.split(":");
                //确保传入的数据符合"属性ID:属性值ID"的约定格式，避免因格式错误导致查询条件构建失败
                if (null != split && split.length == 2) {
                    boolQuery.filter(f -> f.nested(n -> n.path("attributeValueIndexList")
                            .query(q -> q.bool(b -> b.must(m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
                                    .must(m -> m.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))))));
                }
            }
        }
        //排序:@Schema(description = "排序（综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc]；asc:升序 desc:降序）")
        // 1：综合排序 2：播放量 3：最近更新
        String order = albumIndexQuery.getOrder();
        //判断是否有排序功能
        if (!StringUtils.isEmpty(order)) {
            //仍然需要切割
            String[] split = order.split(":");
            if (null != split && split.length == 2) {
                String field = "";
                switch (split[0]) {
                    case "1":
                        field = "hotScore";
                        break;
                    case "2":
                        field = "playStatNum";
                        break;
                    case "3":
                        field = "createTime";
                        break;
                }
                //设置排序字段
                String finalField = field;
                searchRequestBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }
        //分页
        Integer from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(albumIndexQuery.getPageSize());
        //将bool-->query中
        searchRequestBuilder.query(boolQuery.build()._toQuery());
        SearchRequest searchRequest = searchRequestBuilder.build();
        //打印DSL语句
        System.out.println("dsl:" + searchRequest.toString());
        return searchRequest;
    }

    /**
     * 专辑下架
     *
     * @param albumId
     */
    @Override
    public void lowerAlbum(Long albumId) {
        //利用es的API,对数据进行删除
        albumIndexRepository.deleteById(albumId);

    }


    /**
     * 获取频道页数据
     *
     * @param category1Id
     * @return
     */
    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        //map.put("baseCategory3",三级分类对象)
        //map.put("list",专辑集合列表)
        //从mapkey对应的value入手分析实现过程
        //先通过一级分类Id获取到三级分类列表
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);
        //判断
        Assert.notNull(baseCategory3ListResult, "查询三级分类集合失败");
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "获取三级分类集合数据失败");
        //通过这个集合获取到三级分类Id集合
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        //这里还涉及到类型转换问题:List<Long>-->List<FieldValue> v,因为下边专辑集合列表当中是List<FieldValue> v
        /*
        public static FieldValue of(long value) {
		    return new FieldValue(Kind.Long, value);
	    }
         */
        List<FieldValue> fieldValueList = baseCategory3List.stream().map(baseCategory3 -> FieldValue.of(baseCategory3.getId())).collect(Collectors.toList());
        //通过三级分类Id查找三级分类对象category3Id-->BaseCategory3    baseCategory3 -> baseCategory3可以用Function.identity()写
        Map<Long, BaseCategory3> category3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, Function.identity()));
        //专辑集合列表
        //t1->t1.value()的属性:List<FieldValue> v
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id")
                                    .terms(t1 -> t1.value(fieldValueList))))
                            .aggregations("agg_category3Id", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("topSixHotScoreAgg", a1 -> a1.topHits(t1 -> t1.size(6)
                                            .sort(s1 -> s1.field(f -> f.field("hotScore").order(SortOrder.Desc))))))
                    , AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //获取结果组装数据,从agg里取数据
        Aggregate aggregate = searchResponse.aggregations().get("agg_category3Id");
        List<Map<String, Object>> list = aggregate.lterms().buckets().array().stream().map(bucket -> {
            //存储数据我需要创建一个map集合
            HashMap<String, Object> map = new HashMap<>();
            //先获取key
            long category3Id = bucket.key();
            //存储第一个三级分类对象
            map.put("baseCategory3", category3Map.get(category3Id));
            //获取专辑集合列表
            /*
            hit->{
                        JsonData source = hit.source();
                        AlbumInfoIndex albumInfoIndex = JSON.parseObject(source.toString(), AlbumInfoIndex.class);
             */
            Aggregate topSixHotScoreAgg = bucket.aggregations().get("topSixHotScoreAgg");
            List<AlbumInfoIndex> albumInfoIndexList = topSixHotScoreAgg.topHits().hits().hits().stream().
                    map(hit -> JSON.parseObject(hit.source().toString(), AlbumInfoIndex.class))
                    .collect(Collectors.toList());
            map.put("list", albumInfoIndexList);
            //返回map
            return map;
        }).collect(Collectors.toList());

        //返回数据
        return list;
    }

    /**
     * 更新排行榜
     */
    @Override
    public void updateLatelyAlbumRanking() {
        //获取所有一级分类数据
        Result<List<BaseCategory1>> listResult = categoryFeignClient.findAllCategory1();
        Assert.notNull(listResult, "查询一级分类数据失败");
        List<BaseCategory1> baseCategory1List = listResult.getData();
        Assert.notNull(baseCategory1List, "查询一级分类数据失败");
        //获取排序的维度
        String[] split = rankingDimensionArray.split(",");
        //循环遍历集合 调用es客户端生成dsl语句并执行 获取结果集放入缓存
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            Long category1Id = baseCategory1.getId();//目的是组装dsl语句
            for (String ranking : split) {
                //dsl语句 调用es API
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(
                            s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(category1Id)))
                                    .sort(s1 -> s1.field(f -> f.field(ranking).order(SortOrder.Desc)))
                            , AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //获取集合列表
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(hit -> hit.source()).collect(Collectors.toList());//数据有长度限制,所以这里得tolist
                //将每次获取的数据添加到缓存中
                redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX+category1Id,ranking,albumInfoIndexList);

            }

        }
    }

    /**
     * 获取排行榜
     * @param category1Id
     * @param ranking
     * @return
     */
    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String ranking) {
        return (List<AlbumInfoIndex>) redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX+category1Id,ranking);
    }
}
